package article

import (
	"context"

	"BookStack/pkg/errors"
)

// Service 文章领域服务接口
type Service interface {
	// 文章基本操作
	Create(ctx context.Context, title, content, summary string, authorID, categoryID uint, coverImage string, customSlug string) (*Article, error)
	GetByID(ctx context.Context, id uint) (*Article, error)
	GetBySlug(ctx context.Context, slug string) (*Article, error)
	Update(ctx context.Context, id uint, title, content, summary string, categoryID uint, coverImage string) (*Article, error)
	Delete(ctx context.Context, id uint) error

	// 文章列表查询
	List(ctx context.Context, page, pageSize int, filters map[string]interface{}) ([]*Article, int64, error)
	ListByAuthor(ctx context.Context, authorID uint, page, pageSize int) ([]*Article, int64, error)
	ListByCategory(ctx context.Context, categoryID uint, page, pageSize int) ([]*Article, int64, error)
	ListRecommended(ctx context.Context, page, pageSize int) ([]*Article, int64, error)

	// 文章状态管理
	Publish(ctx context.Context, id uint) (*Article, error)
	Archive(ctx context.Context, id uint) (*Article, error)
	Draft(ctx context.Context, id uint) (*Article, error)
	SetStatus(ctx context.Context, id, status uint) (*Article, error)
	SetRecommend(ctx context.Context, id uint, isRecommend bool) (*Article, error)

	// 文章统计相关
	IncrementViews(ctx context.Context, id uint) error
	IncrementLikes(ctx context.Context, id uint) error
	DecrementLikes(ctx context.Context, id uint) error
	IncrementComments(ctx context.Context, id uint) error
	DecrementComments(ctx context.Context, id uint) error
}

// articleService 文章领域服务实现
type articleService struct {
	repo Repository
}

// NewArticleService 创建文章服务
func NewArticleService(repo Repository) Service {
	return &articleService{
		repo: repo,
	}
}

// Create 创建文章
func (s *articleService) Create(ctx context.Context, title, content, summary string, authorID, categoryID uint, coverImage string, customSlug string) (*Article, error) {
	// 创建文章实体
	article, err := NewArticle(title, content, summary, authorID, categoryID, coverImage, customSlug)
	if err != nil {
		return nil, err
	}

	// 检查slug是否已存在
	exists, err := s.repo.ExistsBySlug(ctx, article.Slug, 0)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if exists {
		return nil, errors.New(errors.ErrCodeArticleAlreadyExists, "").WithDetails(map[string]interface{}{
			"slug": article.Slug,
		})
	}

	// 保存到仓储
	if err := s.repo.Create(ctx, article); err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return article, nil
}

// GetByID 通过ID获取文章
func (s *articleService) GetByID(ctx context.Context, id uint) (*Article, error) {
	article, err := s.repo.GetByID(ctx, id)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if article == nil {
		return nil, errors.New(errors.ErrCodeArticleNotFound, "").WithDetails(map[string]interface{}{
			"article_id": id,
		})
	}
	return article, nil
}

// GetBySlug 通过Slug获取文章
func (s *articleService) GetBySlug(ctx context.Context, slug string) (*Article, error) {
	article, err := s.repo.GetBySlug(ctx, slug)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if article == nil {
		return nil, errors.New(errors.ErrCodeArticleNotFound, "").WithDetails(map[string]interface{}{
			"article_slug": slug,
		})
	}
	return article, nil
}

// Update 更新文章
func (s *articleService) Update(ctx context.Context, id uint, title, content, summary string, categoryID uint, coverImage string) (*Article, error) {
	// 获取文章
	article, err := s.repo.GetByID(ctx, id)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if article == nil {
		return nil, errors.New(errors.ErrCodeArticleNotFound, "").WithDetails(map[string]interface{}{
			"article_id": id,
		})
	}

	// 如果标题变更，需要检查新生成的slug是否已存在
	oldTitle := article.Title
	if oldTitle != title {
		// 临时计算新的slug以进行检查
		newSlug := generateSlug(title)
		exists, err := s.repo.ExistsBySlug(ctx, newSlug, id)
		if err != nil {
			return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
		}
		if exists {
			return nil, errors.New(errors.ErrCodeArticleAlreadyExists, "").WithDetails(map[string]interface{}{
				"slug": newSlug,
			})
		}
	}

	// 更新文章
	if err := article.Update(title, content, summary, categoryID, coverImage); err != nil {
		return nil, err
	}

	// 保存到仓储
	if err := s.repo.Update(ctx, article); err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return article, nil
}

// Delete 删除文章
func (s *articleService) Delete(ctx context.Context, id uint) error {
	// 检查文章是否存在
	article, err := s.repo.GetByID(ctx, id)
	if err != nil {
		return errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if article == nil {
		return errors.New(errors.ErrCodeArticleNotFound, "").WithDetails(map[string]interface{}{
			"article_id": id,
		})
	}

	// 删除文章
	if err := s.repo.Delete(ctx, id); err != nil {
		return errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return nil
}

// List 获取文章列表
func (s *articleService) List(ctx context.Context, page, pageSize int, filters map[string]interface{}) ([]*Article, int64, error) {
	offset := (page - 1) * pageSize
	articles, total, err := s.repo.List(ctx, offset, pageSize, filters)
	if err != nil {
		return nil, 0, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	return articles, total, nil
}

// ListByAuthor 获取作者的文章列表
func (s *articleService) ListByAuthor(ctx context.Context, authorID uint, page, pageSize int) ([]*Article, int64, error) {
	offset := (page - 1) * pageSize
	articles, total, err := s.repo.ListByAuthor(ctx, authorID, offset, pageSize)
	if err != nil {
		return nil, 0, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	return articles, total, nil
}

// ListByCategory 获取分类下的文章列表
func (s *articleService) ListByCategory(ctx context.Context, categoryID uint, page, pageSize int) ([]*Article, int64, error) {
	offset := (page - 1) * pageSize
	articles, total, err := s.repo.ListByCategory(ctx, categoryID, offset, pageSize)
	if err != nil {
		return nil, 0, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	return articles, total, nil
}

// ListRecommended 获取推荐文章列表
func (s *articleService) ListRecommended(ctx context.Context, page, pageSize int) ([]*Article, int64, error) {
	offset := (page - 1) * pageSize
	articles, total, err := s.repo.ListRecommended(ctx, offset, pageSize)
	if err != nil {
		return nil, 0, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	return articles, total, nil
}

// Publish 发布文章
func (s *articleService) Publish(ctx context.Context, id uint) (*Article, error) {
	// 获取文章
	article, err := s.repo.GetByID(ctx, id)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if article == nil {
		return nil, errors.New(errors.ErrCodeArticleNotFound, "").WithDetails(map[string]interface{}{
			"article_id": id,
		})
	}

	// 发布文章
	if err := article.Publish(); err != nil {
		return nil, err
	}

	// 保存到仓储
	if err := s.repo.Update(ctx, article); err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return article, nil
}

// Archive 归档文章
func (s *articleService) Archive(ctx context.Context, id uint) (*Article, error) {
	// 获取文章
	article, err := s.repo.GetByID(ctx, id)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if article == nil {
		return nil, errors.New(errors.ErrCodeArticleNotFound, "").WithDetails(map[string]interface{}{
			"article_id": id,
		})
	}

	// 归档文章
	if err := article.Archive(); err != nil {
		return nil, err
	}

	// 保存到仓储
	if err := s.repo.Update(ctx, article); err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return article, nil
}

// Draft 设置文章为草稿
func (s *articleService) Draft(ctx context.Context, id uint) (*Article, error) {
	// 获取文章
	article, err := s.repo.GetByID(ctx, id)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if article == nil {
		return nil, errors.New(errors.ErrCodeArticleNotFound, "").WithDetails(map[string]interface{}{
			"article_id": id,
		})
	}

	// 设置为草稿
	if err := article.Draft(); err != nil {
		return nil, err
	}

	// 保存到仓储
	if err := s.repo.Update(ctx, article); err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return article, nil
}

// SetStatus 设置文章状态
func (s *articleService) SetStatus(ctx context.Context, id, status uint) (*Article, error) {
	// 获取文章
	article, err := s.repo.GetByID(ctx, id)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if article == nil {
		return nil, errors.New(errors.ErrCodeArticleNotFound, "").WithDetails(map[string]interface{}{
			"article_id": id,
		})
	}

	// 设置状态
	if err := article.SetStatus(status); err != nil {
		return nil, err
	}

	// 保存到仓储
	if err := s.repo.Update(ctx, article); err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return article, nil
}

// SetRecommend 设置文章推荐状态
func (s *articleService) SetRecommend(ctx context.Context, id uint, isRecommend bool) (*Article, error) {
	// 获取文章
	article, err := s.repo.GetByID(ctx, id)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if article == nil {
		return nil, errors.New(errors.ErrCodeArticleNotFound, "").WithDetails(map[string]interface{}{
			"article_id": id,
		})
	}

	// 设置推荐状态
	article.SetRecommend(isRecommend)

	// 保存到仓储
	if err := s.repo.Update(ctx, article); err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return article, nil
}

// IncrementViews 增加文章浏览量
func (s *articleService) IncrementViews(ctx context.Context, id uint) error {
	err := s.repo.IncrementViews(ctx, id)
	if err != nil {
		return errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	return nil
}

// IncrementLikes 增加文章点赞数
func (s *articleService) IncrementLikes(ctx context.Context, id uint) error {
	err := s.repo.IncrementLikes(ctx, id)
	if err != nil {
		return errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	return nil
}

// DecrementLikes 减少文章点赞数
func (s *articleService) DecrementLikes(ctx context.Context, id uint) error {
	err := s.repo.DecrementLikes(ctx, id)
	if err != nil {
		return errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	return nil
}

// IncrementComments 增加文章评论数
func (s *articleService) IncrementComments(ctx context.Context, id uint) error {
	err := s.repo.IncrementComments(ctx, id)
	if err != nil {
		return errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	return nil
}

// DecrementComments 减少文章评论数
func (s *articleService) DecrementComments(ctx context.Context, id uint) error {
	err := s.repo.DecrementComments(ctx, id)
	if err != nil {
		return errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	return nil
}
